/**
 * File Name   : ProcessService.java
 * Description : 
 */
package feng.process.api.service;

import java.sql.SQLException;
import java.util.List;

import org.apache.log4j.Logger;

import feng.process.ProcessDataInfo;
import feng.process.ProcessObject;
import feng.process.api.bean.ParamProcessCreateBean;
import feng.process.api.user.UserSelecter;
import feng.process.base.bean.StepBean;
import feng.process.base.step.StartStep;
import feng.process.cont.ProcessConst;
import feng.process.dao.QueryDao;
import feng.process.dao.UpdateDao;
import feng.process.dao.bean.ParamProcessInstanceBean;
import feng.process.dao.bean.ParamProcessTaskBean;
import feng.process.util.StringUtil;

/**
 * 流程实例处理Service
 * 
 * @author 冯昌硕
 * @create 2012-10-25 下午10:59:53
 */
public class ProcessService {
    
    private static final Logger log = Logger.getLogger(ProcessService.class);

    /**
     * 数据查询Dao
     */
    private QueryDao queryDao;
    
    /**
     * 数据更新Dao
     */
    private UpdateDao updateDao;
    
    /**
     * 待办人员查询器
     */
    private UserSelecter userSelecter;
    
    public ProcessService() throws Exception {
        queryDao = new QueryDao();
        updateDao = new UpdateDao();
        userSelecter = new UserSelecter();
    }
    
    /**
     * 功能：获取指定流程模板的状态
     * @param templeteName 流程模板
     * @return 模板状态
     *         0：上线（流程模板正常可以使用的状态）；
     *         1：预下线（不可再发起新流程，已经运行的流程还可以执行）；
     *         2：下线（流程不可再发起，已经没有在运行中的流程实例）；
     * @create 2012-10-25 下午11:14:55
     */
    public int getTempleteStatus(String templeteName) {
        Object rsObj = queryDao.queryForObject("process_templete.selProcessTempleteStatus", templeteName);
        if(rsObj == null) {
            return -1;
        }
        return (Integer) rsObj;
    }
    
    /**
     * 功能：发起一个流程
     * @param pcreateBean 流程发起参数
     * @return 流程发起后的实例ID
     * @create 2012-10-28 下午8:06:43
     */
    public long startProcess(ParamProcessCreateBean pcreateBean) {
        long flowId = -1;
        
        try {
            updateDao.startTransaction();
            
            // insProcessInstance操作SQL参数
            ParamProcessInstanceBean paramInstanceBean = new ParamProcessInstanceBean();
            paramInstanceBean.setTempleteName(pcreateBean.getTempleteName());
            paramInstanceBean.setFlowNumber(pcreateBean.getFlowNumber());
            paramInstanceBean.setStartUserId(pcreateBean.getStartUserId());
            paramInstanceBean.setStatus(ProcessConst.PROCESS_INS_STATUS_RUNNING);
            paramInstanceBean.setTitle(pcreateBean.getTitle());
            
            // 往process_instance表中添加流程实例记录
            Object insRsObj = updateDao.insert("process_instance.insProcessInstance", paramInstanceBean);
            if(null == insRsObj) {
                log.info("process_instance.insProcessInstance 添加记录响应结果为 null, 插入流程实例表记录失败.");
                throw new Exception("process_instance.insProcessInstance 添加记录响应结果为 null");
            }
            flowId = (Long) insRsObj;
            log.debug("process_instance.insProcessInstance 操作完毕，返回KEY值：" + flowId);
            
            // 调用StartStep执行发起流程操作的实现类
            ProcessObject processObj = ProcessDataInfo.processMap.get(pcreateBean.getTempleteName());
            StartStep startStep = processObj.getStartStep();
            String nextStepId = startStep.start();
            
            String stepDisName = null;     // 环节显示名
            String stepUserSelRole = null; // 环节人员查询规则
            
            List<StepBean> stepBeanLst = processObj.getStepBeanLst();
            for(StepBean stepBean : stepBeanLst) {
                if(nextStepId.equals(stepBean.getId())) {
                    stepDisName = stepBean.getDisplayName();
                    stepUserSelRole = stepBean.getUserSelRole();
                    break;
                }
            }
            
            // 往process_task表中生成任务记录
            ParamProcessTaskBean paramTaskBean = new ParamProcessTaskBean();
            paramTaskBean.setFlowId(flowId);
            paramTaskBean.setStatus(ProcessConst.PROCESS_TASK_STATUS_WAITING);
            paramTaskBean.setStepId(nextStepId);
            paramTaskBean.setStepDisplayName(stepDisName);
            
            long tkid = 0L;
            Object insTaskRsObj = updateDao.insert("process_task.insProcessTask", paramTaskBean);
            if(null == insTaskRsObj) {
                log.info("process_task.insProcessTask 添加记录响应结果为 null, 插入任务表记录失败.");
                throw new Exception("process_task.insProcessTask 添加记录响应结果为 null");
            }
            
            tkid = (Long)insTaskRsObj;
            log.debug("process_task.insProcessTask 执行后环节ID=["+ tkid +"]");
            
            // 取下一环节待办人员
            List<?> stepUsersLst = null;
            //List<?> stepUsersLst = userSelecter.getUsersLst(stepUserSelRole, pcreateBean.getTempleteName(), nextStepId);
            // 动态指定下一环节的待办人员
            if(ProcessConst.TASK_USER_SEL_ROLE_DYNSPECIFY.equalsIgnoreCase(stepUserSelRole)) {
                // 如果是由上一环节指定下一环节的待办人员，则需要由API调用时传入要分配任务给哪些人。
                // 且多个人员的时候，各人员ID之间要用英文逗号分隔
                String nextWaitUsers = pcreateBean.getNextStepWaitUsers();
                stepUsersLst = StringUtil.splitStrToList(nextWaitUsers, ProcessConst.SYS_CHAR_COMMA);
            } else {
                stepUsersLst = userSelecter.getUsersLst(stepUserSelRole, pcreateBean.getTempleteName(), nextStepId);
            }
            
            // 待办人员写任务关系表
            log.debug("流程["+pcreateBean.getTempleteName()+"]环节["+nextStepId+"]待办人员：["+stepUsersLst+"]");
            int waitUserInsRs = updateDao.batchExecuteWaitUser(stepUsersLst, tkid);
            log.debug("流程["+pcreateBean.getTempleteName()+"]环节["+nextStepId+"]待办人员：["+stepUsersLst+"] 批理插入结果 =["+waitUserInsRs+"]");
            
            updateDao.commitTransaction();
        } catch (SQLException e) {
            log.error("发起"+pcreateBean.getTempleteName()+"流程实例SQLException：" + e.toString());
            e.printStackTrace();
        } catch(Exception e) {
            log.error("发起"+pcreateBean.getTempleteName()+"流程实例Exception：" + e.toString());
            e.printStackTrace();
        } finally {
            try {
                updateDao.endTransaction();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        
        return flowId;
    }
    
    /**
     * 删除指定的流程实例内容，执行该操作后会删除流程实例相关的记录
     * @param flowId
     * @return
     * @create 2012-11-6 下午11:10:38
     */
    public boolean deleteProcessInstance(long flowId) {
        boolean result = false;
        try {
            // 开启事务
            log.debug("准备删除流程实例,flowId=["+ flowId +"], 开启事务");
            updateDao.startTransaction();
            
            // 删除表process_task_user_ref中的记录
            int pturRs = updateDao.delete("process_task_user_ref.delTaskUserRefByFlowId", flowId);
            log.debug("流程实例["+ flowId +"]删除process_task_user_ref记录的处理结果=["+ pturRs +"]");
            if(pturRs <= 0) {
                log.info("流程实例["+ flowId +"]删除process_task_user_ref记录处理未成功");
                throw new Exception("流程实例["+ flowId +"]删除process_task_user_ref记录数不大于0");
            }
            
            // 删除表process_task中的记录
            int ptRs = updateDao.delete("process_task.delTaskByFlowId", flowId);
            log.debug("流程实例["+ flowId +"]删除process_task记录的处理结果=["+ ptRs +"]");
            if(ptRs <= 0) {
                log.info("流程实例["+ flowId +"]删除process_task记录处理未成功");
                throw new Exception("流程实例["+ flowId +"]删除process_task记录数不大于0");
            }
            
            // 删除表process_instance中的记录
            int piRs = updateDao.delete("process_instance.delInstanceByFlowId", flowId);
            log.debug("流程实例["+ flowId +"]删除process_instance记录的处理结果=["+ piRs +"]");
            if(ptRs <= 0) {
                log.info("流程实例["+ flowId +"]删除process_instance记录处理未成功");
                throw new Exception("流程实例["+ flowId +"]删除process_instance记录数不大于0");
            }
            
            updateDao.commitTransaction();
            
            result = true;
        } catch (SQLException e) {
            log.error("删除流程实例["+ flowId +"] SQLException：" + e.toString());
            e.printStackTrace();
        } catch (Exception e) {
            log.error("删除流程实例["+ flowId +"] Exception：" + e.toString());
            e.printStackTrace();
        } finally {
            try {
                updateDao.endTransaction();
                log.debug("删除流程实例,flowId=["+ flowId +"], 结束事务");
            } catch (SQLException e1) {
                log.debug("删除流程实例,flowId=["+ flowId +"], 结束事务异常:" + e1.toString());
                e1.printStackTrace();
            }
        }
        
        return result;
    }
    
//    /**
//     * 批量操作插入待办人员与环节的关系表
//     * @param userLst 环节待办人员
//     * @param tkid 环节ID
//     * @return 批量处理结果
//     * @throws SQLException
//     * @create 2012-10-29 下午9:02:56
//     */
//    private int batchExecuteWaitUser(List<?> userLst, long tkid) throws SQLException {
//        if((null == userLst) || (userLst.size() <= 0)) {
//            log.info("查询的用户列表为空，不作待办人员添加处理");
//            return -1;
//        }
//        
//        updateDao.startBatch();
//        
//        String userId = null;
//        ParamTaskUserRefBean taskUserBean = null;
//        int userLstSize = userLst.size();
//        for(int i = 0; i < userLstSize; i++) {
//            userId = (String) userLst.get(i);
//            taskUserBean = new ParamTaskUserRefBean();
//            taskUserBean.setTkid(tkid);
//            taskUserBean.setWaitUserId(userId);
//            updateDao.insert("process_task_user_ref.insTaskWaitUsers", taskUserBean);
//        }
//        
//        int batchExeRs = updateDao.executeBatch();
//        return batchExeRs;
//    }
}
